from typing import Union

from entity import organizations as o
from util import public_tools as tool
from util import io_tools as io
import datetime
import calendar


def load_emp_data() -> None:
    """
    加载所有数据
    :return: None
    """
    io.checking_data_files()
    io.load_users()
    io.load_lock_record()
    io.load_employee_info()
    io.load_employee_pic()


def add_new_employee(name: str) -> str:
    """
    添加新员工到系统并生成唯一特征码。
        该函数会自动完成以下操作：
        1. 生成唯一的员工ID
        2. 生成随机特征码
        3. 创建员工对象并添加到组织结构
        4. 持久化保存最新的员工信息
    :param name:新员工姓名
    :return:code:为新员工生成的特征码
    """
    code = tool.randomCode()  # 生成随机特征码
    newEmp = o.Employee(o.get_new_id(), name, code)  # 创建员工对象
    o.add(newEmp)  # 组织结构中添加新员工
    io.save_employee_all()  # 保存最新的员工信息
    # print(f"特征码:{code}")
    return code  # 新员工的特征码


def remove_employee(id: str) -> None:
    """
    删除已有员工资料
    :param id:
        str: 参数为员工编号
    :return:
        None
    """
    io.remove_pics(id)   #删除改员工所有图片
    o.remove(id)  #从组织结构中删除
    io.save_employee_all() #保存最新的员工数据
    io.save_lock_record() #保存最新的打卡记录


def add_lock_record(name: str) -> None:
    """
    添加员工打卡记录
    :param name: name 打卡员工姓名
    :return: None
    """
    record = o.LOCK_RECORD
    now_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    if name in record.keys():
        r_list = record[name]
        if len(r_list) == 0:
            r_list = list()
        r_list.append(now_time)
    else:
        r_list = list()
        r_list.append(now_time)
        record[name] = r_list
    io.save_lock_record()



def get_employee_report() -> str:
    """
    获取员工数据
    返回一个包含所有员工简要信息的报表，展示员工列表
    :return:report:员工报表
    """
    # report = list()
    report = "##################\n"
    report += "员工名单如下：\n"
    i = 0
    for emp in o.EMPLOYEES:
        report += "(" + str(emp.id) + ")" + emp.name + "\t"
        i += 1
        if i == 4:
            report += "\n"
            i = 0
    report = report.strip()
    report += "\n##################"
    return report



def get_record_all():
    """
    获取所有员工的打卡记录信息
    :return: report:打卡记录报表
    """
    record = o.LOCK_RECORD  # 获得打卡记录字典
    report = ""  # 报表内容
    for name in record.keys():  # 遍历所有名字
        report += "-----------------------------------\n"
        report += name + "  打卡记录如下：\n"
        for date in record[name]:  # 遍历所有时间字符串
            report += date + "\n"
    return report


def check_id(id: Union[int, str]) -> bool:
    """
    检查员工ID是否存在于系统中。
    :param id:
        需要检查的员工ID
    :return:
        bool: 如果ID存在返回True，否则返回False
    """
    if id is None or str(id).strip() == "":
        raise ValueError("员工ID不能为空")

    # 转换为字符串进行比较
    target_id = str(id).strip()

    # 遍历员工列表检查ID
    for emp in o.EMPLOYEES:
        if target_id == str(emp.id).strip():
            return True
    return False


def get_name_with_code(code: str) -> str:
    """
    通过员工特征码获取员工姓名
    :param code: 该员工的特征码
    :return: 员工姓名name
    """
    for emp in o.EMPLOYEES:
        if str(code) == str(emp.code):
            return emp.name


def get_code_with_id(id: str) -> str:
    """
    通过员工编号获取员工的特征码
    :param id: 员工编号
    :return: 员工特征码code
    """
    for emp in o.EMPLOYEES:
        if str(id) == str(emp.id):
            return emp.code


def valid_users(username, password):
    """
    验证管理员账号和密码
    :param username: 管理员账号
    :param password: 管理员密码
    :return: 管理员账号存在且密码正确返回Ture，反之返回False
    """
    if username in o.USERS.keys():
        if o.USERS.get(username) == password:
            return True
    return False


def save_work_time(work_time, close_time):
    """
    保存用户设置的上下班时间，第一个时间为上班时间，第二个为下班时间
    都为 str 且必须符合 "%H:%M:%S"
    :param work_time: 上班时间 "%H:%M:%S"
    :param close_time: 下班时间 "%H:%M:%S"
    :return: None
    """
    o.WORK_TIME = work_time
    o.CLOSING_TIME = close_time
    io.save_work_time_config()


def get_day_report(data):
    """
    打印指定的考勤日报
    :param data: 指定的日期 str "%Y-%m-%d"
    :return: None
    """
    io.load_work_time_config()
    #当天0点
    earliest_time = datetime.datetime.strptime(data + "00:00:00", "%Y-%m-%d%H:%M:%S")
    #当天中午12点
    noon_time = datetime.datetime.strptime(data + "12:00:00", "%Y-%m-%d%H:%M:%S")
    #当天晚上0点之前
    latest_time = datetime.datetime.strptime(data + "23:59:59", "%Y-%m-%d%H:%M:%S")
    #上班时间
    work_time = datetime.datetime.strptime(data + "" + o.WORK_TIME, "%Y-%m-%d%H:%M:%S")
    #下班时间
    closing_time = datetime.datetime.strptime(data + "" + o.CLOSING_TIME, "%Y-%m-%d%H:%M:%S")

    late_list = []      #迟到名单
    left_list = []      #早退名单
    absent_list = []    #缺席名单

    for emp in o.EMPLOYEES:                                 #遍历所有员工
        if emp.name in o.LOCK_RECORD.keys():                #如果该员工有打卡记录
            emp_lock_list = o.LOCK_RECORD.get(emp.name)     #获取该员工所有打卡记录
            is_absent = True                                #缺席状态
            for lock_time_str in emp_lock_list:             #遍历所有打卡记录
                lock_time = datetime.datetime.strptime(lock_time_str, "%Y-%m-%d %H:%M:%S")      #打卡记录转为日期格式
                if earliest_time < lock_time < latest_time: #当天有打卡记录
                    is_absent = False                       #不缺席
                    if work_time < lock_time <= noon_time:  #上班时间后、中午之前打卡
                        late_list.append(emp.name)          #加入迟到名单
                    if noon_time < lock_time < closing_time:#中午之后、下班之前打卡
                        left_list.append(emp.name)          #加入早退名单
            if is_absent:                                   #如果仍是缺席状态
                absent_list.append(emp.name)                #加入缺席名单
        else:                                               #该员工没有打卡记录
            absent_list.append(emp.name)                    #加入缺席名单

    emp_count = len(o.EMPLOYEES)                            #员工总数
    print("--------" + data + "--------")
    print("应到人数：" + str(emp_count))
    print("缺席人数：" + str(len(absent_list)))
    absent_name = ""
    if len(absent_list) == 0:
        absent_name = "(空)"
    else:
        for name in absent_list:
            absent_name += name + " "
    print("缺席名单：" + str(absent_name))
    print("迟到人数：" + str(len(late_list)))
    late_name = ""
    if len(late_list) == 0:
        late_name = "(空)"
    else:
        for name in late_list:
            late_name += name + " "
    print("迟到名单：" + str(late_name))
    print("早退人数：" + str(len(left_list)))
    left_name = ""
    if len(left_list) == 0:
        left_name = "(空)"
    else:
        for name in left_list:
            left_name += name + " "
    print("早退名单：" + str(left_name))


def get_today_report():
    """
    打印当天的日报:\n
    将当天的日期生成str(data)\n
    调用get_day_report()
    :return: None
    """
    data = datetime.datetime.now().strftime("%Y-%m-%d")
    get_day_report(str(data))


def get_month_report(month):
    io.load_work_time_config()
    data = datetime.datetime.strptime(month, "%Y-%m")
    monthRange = calendar.monthrange(data.year, data.month)[1]
    month_first_day = datetime.date(data.year, data.month,1)
    month_last_day = datetime.date(data.year, data.month, monthRange)


    clock_in = "I"
    clock_out = "O"
    late = "L"
    left_early = "E"
    absent = "A"


    lock_report = dict()

    for emp in o.EMPLOYEES:  # 遍历所有员工
        emp_lock_data = []
        if emp.name in o.LOCK_RECORD.keys():  # 如果该员工有打卡记录
            emp_lock_list = o.LOCK_RECORD.get(emp.name)  # 获取该员工所有打卡记录
            index_day = month_first_day
            while index_day <= month_last_day:
                is_absent = True
                # 当天0点
                earliest_time = datetime.datetime.strptime(str(index_day) + "00:00:00", "%Y-%m-%d%H:%M:%S")
                # 当天中午12点
                noon_time = datetime.datetime.strptime(str(index_day) + "12:00:00", "%Y-%m-%d%H:%M:%S")
                # 当天晚上0点之前
                latest_time = datetime.datetime.strptime(str(index_day) + "23:59:59", "%Y-%m-%d%H:%M:%S")
                # 上班时间
                work_time = datetime.datetime.strptime(str(index_day) + "" + o.WORK_TIME, "%Y-%m-%d%H:%M:%S")
                # 下班时间
                closing_time = datetime.datetime.strptime(str(index_day) + "" + o.CLOSING_TIME, "%Y-%m-%d%H:%M:%S")

                emp_today_data = ""

                for lock_time_str in emp_lock_list:  # 遍历所有打卡记录
                    lock_time = datetime.datetime.strptime(lock_time_str, "%Y-%m-%d %H:%M:%S")  # 打卡记录转为日期格式
                    if earliest_time < lock_time < latest_time:  # 当天有打卡记录
                        is_absent = False  # 不缺席
                        if lock_time <= work_time:  #上班时间前打卡
                            emp_today_data += clock_in  #追加正常上班时间打卡标志
                        elif lock_time >= closing_time:  #下班时间后打卡
                            emp_today_data += clock_out  #追加正常下班时间打卡标志
                        elif work_time < lock_time <=noon_time:
                            emp_today_data += late
                        elif noon_time < lock_time <= closing_time:
                            emp_today_data += left_early
                if is_absent:  # 如果仍是缺席状态
                    emp_today_data = absent # 直接赋予缺席标志
                emp_lock_data.append(emp_today_data)    #员工打卡标记添加到打卡情况列表中
                index_day = index_day + datetime.timedelta(days=1)
        else:  # 该员工没有打卡记录
            index_day = month_first_day
            while index_day <= month_last_day:
                emp_lock_data.append(absent)
                index_day = index_day + datetime.timedelta(days=1)
        lock_report[emp.name] = emp_lock_data

    report = "日期：\n"
    index_day = month_first_day
    work_day = 0
    while index_day <= month_last_day:
        report += "| " + str(index_day) + " "
        index_day += datetime.timedelta(days=1)
        work_day += 1
    report += "|\n\n"

    for emp in lock_report.keys():
        report += "姓名：" + emp + "\n"
        ab_time, ci_time, co_time, la_time, le_time = 0, 0, 0, 0, 0
        data_list = lock_report.get(emp)
        for data in data_list:
            text = ""
            if absent == data:
                text = "【缺席】"
                ab_time += 1
            elif clock_in in data and clock_out in data:
                text = ""
            else:
                if late in data and clock_in not in data:
                    text += "【迟到】"
                    la_time += 1
                if left_early in data and clock_out not in data:
                    text += "【早退】"
                    le_time += 1
                if clock_out not in data and left_early not in data:
                    text += "【下班未打卡】"
                    co_time += 1
                if clock_in in data and late not in data:
                    text += "【上班未打卡】"
                    ci_time += 1
            report += "" + text + "" + ","
        report += "\n"
        abnormal_time = sum([ab_time, ci_time, co_time, la_time, le_time])
        normal_business_time = work_day - abnormal_time
        report += f"统计：正常通勤：{normal_business_time}  缺席:{ab_time}, 迟到:{la_time}, 早退:{le_time}, 上班未打卡:{ci_time},下班未打卡:{co_time} \n"
        report += "\n"
    print(report)
    title_data = month_first_day.strftime("%Y{y}%m{m}").format(y = "年", m = "月")
    file_name = title_data + "考勤报表"
    io.create_CSV(file_name, report)

def get_pre_month_report():
    """
    创建上个月打卡记录月报
    :return: None
    """
    today = datetime.date.today()
    pre_month_first_day = datetime.date(today.year, today.month - 1,1)
    pre_month = pre_month_first_day.strftime("%Y-%m")
    get_month_report(pre_month)


def check_duplicate_name(name: str) -> bool:
    """
    判断名称是否在员工列表中存在重复
    :param name: 新员工名称
    :return: bool: 符合格式返回True，否则返回False
    """
    for emp in o.EMPLOYEES:
        if str(name) == str(emp.name):
            return True
    return False


def show_employee_all():
    """
    显示系统中所有员工的详细信息。

    该函数会获取并格式化所有员工的信息，然后以表格形式输出到控制台。
    支持中文字符对齐，并按员工ID排序展示。

    返回:
        None

    异常:
        Exception: 当获取员工信息失败时抛出

    示例:
        >>> show_employee_all()
        +----+--------+-----------+
        | ID | 姓名   | 特征码    |
        +----+--------+-----------+
        | 1  | 张三   | EMP001    |
        | 2  | 李四   | EMP002    |
        | 3  | 王五   | EMP003    |
        +----+--------+-----------+
    """
    employees = o.EMPLOYEES

    if not employees:
        print("当前系统中没有员工记录。")
        return

    # 按员工ID排序
    employees.sort(key=lambda emp: emp.id)

    # 计算各列的最大宽度，确保表格对齐
    max_id_width = max(len(str(emp.id)) for emp in employees)
    max_name_width = max(len(emp.name) for emp in employees)
    max_code_width = max(len(emp.code) for emp in employees)

    # 确保列宽至少为标题宽度
    max_id_width = max(max_id_width, 2)  # "ID"的宽度
    max_name_width = max(max_name_width, 4)  # "姓名"的宽度
    max_code_width = max(max_code_width, 6)  # "特征码"的宽度

    # 构建表格
    header = f"| ID{' ' * (max_id_width - 2)} | 姓名{' ' * (max_name_width - 4)} | 特征码{' ' * (max_code_width - 6)} |"
    separator = f"+{'-' * (max_id_width + 2)}+{'-' * (max_name_width + 4)}+{'-' * (max_code_width + 6)}+"

    print(separator)
    print(header)
    print(separator)

    for emp in employees:
        # 计算填充空格数，确保中文对齐
        id_padding = max_id_width - len(str(emp.id))
        name_padding = max_name_width - len(emp.name)
        code_padding = max_code_width - len(emp.code)

        # 格式化并输出员工信息行
        print(f"| {emp.id}{' ' * id_padding} | {emp.name}{' ' * name_padding} | {emp.code}{' ' * code_padding} |")

    print(separator)
